/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.lock.extension.jpa;

import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import io.iec.edp.caf.commons.entity.CAFContextInfo;
import io.iec.edp.caf.commons.spi.utils.CAFContextResolverUtils;
import io.iec.edp.caf.commons.transaction.JpaTransaction;
import io.iec.edp.caf.commons.transaction.TransactionPropagation;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.commons.utils.StringUtils;
import io.iec.edp.caf.lock.service.api.api.LockExtension;
import io.iec.edp.caf.lock.service.api.api.RemoveLockInstance;
import io.iec.edp.caf.lock.service.api.exception.DLErrorDefinition;
import io.iec.edp.caf.lock.service.api.repositories.BatchLockRepo;
import io.iec.edp.caf.lock.service.api.repositories.LockRepo;
import io.iec.edp.caf.lock.service.api.utils.DataValidator;
import io.iec.edp.caf.lock.service.spi.utils.LockValidateResolverUtils;
import io.iec.edp.caf.lockservice.api.*;
import lombok.extern.slf4j.Slf4j;
import lombok.var;

import javax.persistence.EntityManager;
import java.sql.SQLTransientConnectionException;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class JpaLockExtensionImpl implements LockExtension {

    private LockRepo repo;
    // @Autowired
    private BatchLockRepo batchRepo;

    private static int batchSize=0;

    public JpaLockExtensionImpl(LockRepo repo, BatchLockRepo batchRepo){
        this.repo=repo;
        this.batchRepo=batchRepo;
    }

    @Override
    public LockResult addLock(String mkId, String dataCat, String dataId, DataLockOptions option, String funcId, String comment){
        CAFContextInfo contextInfo= CAFContextResolverUtils.getCAFContextInfo();
        String lockId = UUID.randomUUID().toString();
        LockEntity entity = this.createLockEntity(lockId, mkId, dataCat, dataId, option, funcId, comment,contextInfo);
        long time = System.currentTimeMillis();
        LockResult result = new LockResult();
        //结果默认为不成功
        result.setSuccess(false);

        JpaTransaction tran = JpaTransaction.getTransaction();
        try {
            tran.begin(TransactionPropagation.REQUIRES_NEW);
            //从数据库获取锁信息
            long time2 = System.currentTimeMillis();
            List<LockEntity> entities = this.repo.findByMkIdAndCategoryIdAndDataId(mkId, dataCat, dataId);
            if(log.isDebugEnabled()){
                long cost2=System.currentTimeMillis()-time2;
                log.debug("selectTime: "+cost2+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat+"-"+dataId);
            }
            // 无锁直接加锁
            if (entities == null || entities.size() == 0) {
                result.setLockedEntities(null);
                long time3 = System.currentTimeMillis();
                this.repo.save(entity);
                if(log.isDebugEnabled()){
                    long cost3=System.currentTimeMillis()-time3;
                    log.debug("noLockAdd: "+cost3+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat+"-"+dataId);
                }
                result.setSuccess(true);
                result.setLockId(entity.getId());
            } else {
                //获取排它锁
                LockStatus lockStatus = this.checkValidate(entities.get(0));
                // 共享锁的处理 - 不检查共享锁的存在性，排它锁存在但可以被替换掉，直接删除排它锁
                if (option.getReplacedScope() == ReplacedScope.Share) {
                    switch (lockStatus) {
                        case Shared:
                        case Unlocked:
                            this.repo.save(entity);
                            result.setSuccess(true);
                            result.setLockId(entity.getId());
                            break;
                        case Invalid:
                        case Replaceable:
                            this.repo.deleteById(entities.get(0).getId());
                            this.repo.save(entity);
                            result.setSuccess(true);
                            result.setLockId(entity.getId());
                            break;
                        case Irreplaceable:
                            result.setLockedEntities(entities);
                            result.setSuccess(false);
                            break;
                    }
                } else {
                    //加日志排查自己锁自己问题
                    if(log.isInfoEnabled()){ //判断一把日志级别可减少序列化过程
                        log.info("exclusive"+mkId+"/"+dataCat+"/"+dataId);
                    }
                    //加排它锁：不存在有效的排它锁 && 不存在有效的共享锁
                    if (lockStatus == LockStatus.Irreplaceable) {
                        result.setLockedEntities(entities);
                        result.setSuccess(false);
                    } else {
                        List<LockStatus> sharedLockStatus = this.checkValidate(entities);
                        // 共享锁，在以下情况不可加锁：1、存在有效且不可替换锁、共享锁（认为不允许替换）；2、存在多个有效可替换锁；
                        boolean validSharedLockExisting = false;
                        if (entities != null && entities.size() > 0) {
                            for (int index = 0; index < entities.size(); index++) {
                                // 锁有效且不可替换
                                if (sharedLockStatus.get(index) == LockStatus.Irreplaceable ||
                                        sharedLockStatus.get(index) == LockStatus.Shared) {
                                    //加日志排查自己锁自己问题
                                    if(log.isInfoEnabled()){ //判断一把日志级别可减少序列化过程
                                        log.info("lockvalid"+mkId+"/"+dataCat+"/"+dataId);
                                    }
                                    result.setLockedEntities(entities);
                                    result.setSuccess(false);
                                    validSharedLockExisting = true;
                                    break;
                                }
                            }
                        }

                        if (validSharedLockExisting == false) {
                            //不存在有效的共享锁
                            long time4 = System.currentTimeMillis();
                            this.repo.deleteInBatch(entities);
                            if(log.isDebugEnabled()){
                                long cost4=System.currentTimeMillis()-time4;
                                log.debug("noShareDelete: "+cost4+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat+"-"+dataId+" entitySize: "+entities.size());
                            }
                            //新加锁
                            this.repo.save(entity);
                            result.setSuccess(true);
                            result.setLockId(entity.getId());

                        }
                    }
                }
            }
            long timeCom=System.currentTimeMillis();
            tran.commit();
            if(log.isDebugEnabled()){
                long costCom=System.currentTimeMillis()-timeCom;
                long costTotal=System.currentTimeMillis()-time;
                log.debug("lockCommit: "+costCom+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat+"-"+dataId);
                log.debug("lockTime: "+costTotal+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat+"-"+dataId);
            }
            return result;
        } catch (Throwable ex) {
            tran.rollback();
            throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.AddLock_GetLock_Error,"addLockGetLockError",ex, ExceptionLevel.Error,false);
        }
    }

    @Override
    public BatchLockResult addBatchLock(String mkId, String dataCat, List<String> dataIds, String groupId, Duration persistenceTime, String funcId, String comment){
        long timeIn=System.currentTimeMillis();
        CAFContextInfo contextInfo=CAFContextResolverUtils.getCAFContextInfo();
        BatchLockResult result=new BatchLockResult();
        result.setGroupId(groupId);
        //清理过期锁
        this.batchRepo.deleteByExpiredTime(OffsetDateTime.now());

        //查询已有的锁数据
        long time2=System.currentTimeMillis();
        List<BatchLockEntity> entities = queryBatchLockEntityByDataIds(mkId, dataCat, dataIds);
        if(log.isDebugEnabled()){
            long cost2=System.currentTimeMillis()-time2;
            log.debug("queryBatchLock: "+cost2+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
        }
        if (entities != null && entities.size() > 0) {
            long time3=System.currentTimeMillis();
            int count = deleteBatchLockBySession(entities);
            if(log.isDebugEnabled()){
                long cost3=System.currentTimeMillis()-time3;
                log.debug("deleteBatchLock: "+cost3+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
            }
            if (entities.size() != count) {
                result.setLockedEntities(entities);
                result.setSuccess(false);
                if(log.isInfoEnabled()){
                    log.info("Cannot add lock.");
                }
                return result;
            }
        }
        JpaTransaction tran = JpaTransaction.getTransaction();
        try {
            tran.begin(TransactionPropagation.REQUIRES_NEW);
            EntityManager em = SpringBeanUtils.getBean(EntityManager.class);
            if(batchSize==0){
                batchSize = CafEnvironment.getEnvironment().getProperty("spring.jpa.properties.jdbc.batch_size",Integer.class,10);
            }

            List<BatchLockEntity> entityList = createBatchEntities(mkId, dataCat, dataIds, groupId, persistenceTime, funcId, comment,contextInfo);
            long time4=System.currentTimeMillis();
            for (int i = 0; i < entityList.size(); i++) {
                em.persist(entityList.get(i));
                if ((i+1) % batchSize == 0 || i == entityList.size() - 1) {
                    em.flush();
                    em.clear();
                }
            }
            if(log.isDebugEnabled()){
                long cost4=System.currentTimeMillis()-time4;
                log.debug("saveBatchLock: "+cost4+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
            }
            result.setSuccess(true);
            long time5=System.currentTimeMillis();
            tran.commit();
            if(log.isDebugEnabled()){
                long costCom=System.currentTimeMillis()-time5;
                long costTotal=System.currentTimeMillis()-timeIn;
                log.debug("batchLockCommit: "+costCom+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
                log.debug("batchLockTime: "+costTotal+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
            }
            if(log.isInfoEnabled()){
                log.info("Add lock success.");
            }
            return result;
        } catch (Throwable e) {
            tran.rollback();
            throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.AddBatchLock_Error,"addBatchLockError",e, ExceptionLevel.Error,false);
        }
    }

    @Override
    public boolean removeLock(String lockId){
        DataValidator.checkForEmptyString(lockId, "lockId");
        JpaTransaction tran = JpaTransaction.getTransaction();
        try {
            tran.begin(TransactionPropagation.REQUIRES_NEW);
            if (this.repo.findById(lockId).isPresent()) {
                this.repo.deleteById(lockId);
            }
            tran.commit();
            return true;
        } catch (Throwable e) {
            tran.rollback();
            throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.RemLock_Lockid_Error,"removeLockError",e, ExceptionLevel.Error,false);
        }
    }

    @Override
    public boolean removeLock(RemoveLockInstance removeLockInstance){
        DataValidator.checkForNullReference(removeLockInstance,"removeLockInstance");
        DataValidator.checkForEmptyString(removeLockInstance.getLockId(), "lockId");
        JpaTransaction tran = JpaTransaction.getTransaction();
        boolean flag=false;
        try {
            tran.begin(TransactionPropagation.REQUIRES_NEW);
            if (this.repo.findById(removeLockInstance.getLockId()).isPresent()) {
                this.repo.deleteById(removeLockInstance.getLockId());
            }

            tran.commit();
            flag=true;
        } catch (Throwable e) {
            try{
                tran.rollback();
            }catch (Throwable throwable){
                log.error("rollbackError: ",throwable);
            }

            if(tryRemoveLock(e) &&removeLockInstance.isRetryRemoveLock()){  //当报错是因为java.sql.SQLTransientConnectionException: hikari-cp - Connection is not available, request timed out after 30000ms时，尝试3次重试解锁
                int count=0;
                for(int i=0;i<=2;i++){
                    try{
                        Thread.sleep(1000);
                    }catch (Exception e1){
                        log.error("thread-sleep: ",e1);
                    }
                    JpaTransaction trans = JpaTransaction.getTransaction();
                    try{
                        trans.begin(TransactionPropagation.REQUIRES_NEW);
                        if (this.repo.findById(removeLockInstance.getLockId()).isPresent()) {
                            this.repo.deleteById(removeLockInstance.getLockId());
                        }
                        trans.commit();
                        flag=true;
                        break;
                    }catch (Throwable e2){
                        count++;
                        try{
                            trans.rollback();
                        }catch (Throwable ee){
                            log.error("rollbackError: ",ee);
                        }
                        //尝试解锁时的异常
                        if(count==3){
                            throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.RemLock_Lockid_Error,"retryRemoveLockError",e2, ExceptionLevel.Error,false);
                        }
                        log.error("retryRemoveLock:",e2);
                    }
                }
            }else{
                throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.RemLock_Lockid_Error,"removeLockError",e, ExceptionLevel.Error,false);
            }

        }
        return flag;
    }

    @Override
    public  boolean removeSessionLock(String sessionId, int tenantId){
        DataValidator.checkForEmptyString(sessionId, "sessionId");
        JpaTransaction tran = JpaTransaction.getTransaction();
        try {
            tran.begin(TransactionPropagation.REQUIRES_NEW);
            this.repo.deleteBySessionId(sessionId);
            tran.commit();
            return true;
        } catch (Throwable ex) //没有提供sessionid调用报错a
        {
            tran.rollback();
            throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.RemLock_Sessionid_Error,"removeLockError",ex, ExceptionLevel.Error,false);
        }
    }


    @Override
    public boolean removeBatchLock(String groupId){
        JpaTransaction tran = JpaTransaction.getTransaction();
        try {
            tran.begin(TransactionPropagation.REQUIRES_NEW);
            //若批次号没对应锁则也算删锁成功
            this.batchRepo.deleteByGroupId(groupId);
            tran.commit();
            return true;
        } catch (Throwable ex) //没有提供groupid调用报错
        {
            tran.rollback();
//            throw ex;
            throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.RemLock_BathLock_Error,"removeBatchLockError",ex, ExceptionLevel.Error,false);

        }
    }

    @Override
    public  boolean removeBatchLockByContext(String contextId){
        JpaTransaction tran = JpaTransaction.getTransaction();
        try {
            tran.begin(TransactionPropagation.REQUIRES_NEW);
            //若批次号没对应锁则也算删锁成功
            this.batchRepo.deleteByContextId(contextId);
            tran.commit();
            return true;
        } catch (Throwable ex) //没有提供groupid调用报错
        {
            tran.rollback();
            throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.RemLock_BathLock_Error,"removeBatchLockError",ex, ExceptionLevel.Error,false);
        }
    }

    @Override
    public List<String>  getDataIds(String groupId){
        DataValidator.checkForEmptyString(groupId, "groupId");
        //清理过期锁
        this.batchRepo.deleteByExpiredTime(OffsetDateTime.now());

        List<String> listDataIds=new ArrayList<>();

        List<BatchLockEntity>  batchLockEntities=this.batchRepo.findByGroupId(groupId);
        for(BatchLockEntity batchLockEntity:batchLockEntities){
            listDataIds.add(batchLockEntity.getDataId());
        }
        return  listDataIds;
    }


    @Override
    public LockStatus getLockStatus(LockEntity lockEntity){
        return checkValidate(lockEntity);
    }

    private List<BatchLockEntity> createBatchEntities(String mkId, String dataCat, List<String> dataIds, String groupId, Duration persistenceTime, String funcId, String comment,CAFContextInfo contextInfo) {
        List<BatchLockEntity> entities = new ArrayList<>();
        OffsetDateTime lockTime = OffsetDateTime.now();
        OffsetDateTime expiredTime = (persistenceTime.getSeconds() == 0) ?
                OffsetDateTime.of(2037, 1, 19, 3, 14, 7, 59, ZoneOffset.UTC) : lockTime.plus(persistenceTime.getSeconds(), ChronoUnit.SECONDS);

        String sessionId =""; //this.contextService.getSessionId();
        String contextId ="";// this.contextService.getContextId();
        String userId="";
        String currentSU="";
        if(contextInfo!=null){
            sessionId=contextInfo.getSessionId();
            contextId=contextInfo.getContextId();
            userId=contextInfo.getUserId();
            currentSU=contextInfo.getCurrentSU();
        }
        for (var dataId : dataIds) {
            var entity = new BatchLockEntity();
            entity.setId(UUID.randomUUID().toString());
            entity.setMkId(mkId);
            entity.setCategoryId(dataCat);
            entity.setDataId(dataId);
            entity.setGroupId(groupId);
            entity.setSessionId(sessionId);
            entity.setContextId(contextId);
            entity.setFuncId(funcId);
            entity.setComment(comment);
            entity.setExpiredTime(expiredTime);
            entity.setLockTime(lockTime);
            entity.setUserId(userId);
            entity.setSuName(currentSU);
            entities.add(entity);
        }
        return entities;
    }
    private int deleteBatchLockBySession(List<BatchLockEntity> entities) {
        Map<String, List<BatchLockEntity>> map = (Map)entities.stream().collect(Collectors.groupingBy(BatchLockEntity::getSessionId));
        int count = 0;
        for (Map.Entry<String, List<BatchLockEntity>> m : map.entrySet()) {
            //sessionId不为空 && sessionId已过期，则移除
            if (!StringUtils.isEmpty(m.getKey()) && isSessionNotValid(m.getKey())) {
                List<BatchLockEntity> entityList = (List)m.getValue();

                List<String> ids = new ArrayList<String>();
                for (BatchLockEntity sp : entityList) {
                    ids.add(sp.getId());
                }
                //使用in时各数据库对in参数个数有限制，例如oracle是1000，分批次进行删除,每次删不超过999条
//                this.batchRepo.deleteAllByIdIn(ids);
                int size=ids.size();
                int num=size/999+1;
                if(num==1){
                    this.batchRepo.deleteAllByIdIn(ids);
                }else{
                    for(int i=0;i<num;i++){
                        int start = i * 999;
                        int end = (i + 1) * 999;
                        if (end >= size) {
                            end = size;
                        }
                        this.batchRepo.deleteAllByIdIn(ids.subList(start, end));
                    }
                }
                count += ids.size();
            }
        }

        return count;
    }
    private List<BatchLockEntity> queryBatchLockEntityByDataIds(String mkId, String dataCat, List<String> dataIds) {
        List<BatchLockEntity> entities = new ArrayList<>();
        if (dataIds != null) {
            int size = dataIds.size();//获取dataIds的长度
            int num = size / 999 + 1;//每次查询不超过999条
            if (num == 1 || dataIds == null) {
                return this.batchRepo.findAllByMkIdAndCategoryIdAndDataIdIn(mkId, dataCat, dataIds);
            } else {
                for (int i = 0; i < num; i++) {
                    int start = i * 999;
                    int end = (i + 1) * 999;
                    if (end >= size) {
                        end = size;
                    }
                    List<BatchLockEntity> entitiesSub = this.batchRepo.findAllByMkIdAndCategoryIdAndDataIdIn(mkId, dataCat, dataIds.subList(start, end));
                    entities.addAll(entitiesSub);
                }
            }
        }
        return entities;
    }
    private LockEntity createLockEntity(String lockId, String mkId, String dataCat, String dataId, DataLockOptions option, String funcId, String comment, CAFContextInfo contextInfo) {
        String sessionId ="";// this.contextService.getSessionId();
        String contextId="";
        String currentSU="";
        String userId="";
        if(contextInfo!=null){
            sessionId=contextInfo.getSessionId();
            contextId=contextInfo.getContextId();
            currentSU=contextInfo.getCurrentSU();
            userId=contextInfo.getUserId();
        }
        var entity = new LockEntity();
//        entity.setId(lockId);
        entity.setMkId(mkId);
        entity.setCategoryId(dataCat);
        entity.setDataId(dataId);
        entity.setKeepTime(option.getPersistenceTime());
        entity.setLockedScope(option.getLockedScope());
        entity.setReplacedScope(option.getReplacedScope());
        entity.setFuncId(funcId);
        entity.setSessionId(sessionId);
        entity.setContextId(contextId);
        entity.setComment(comment);
        entity.setUserId(userId);
        entity.setLockTime(OffsetDateTime.now());
        entity.setSuName(currentSU);
        return entity;
    }


    private List<LockStatus> checkValidate(List<LockEntity> locks) {
        List<LockStatus> result = new ArrayList<>();
        if (locks != null && locks.size() > 0) {
            for (int i = 0; i < locks.size(); i++) {
                result.add(checkValidate(locks.get(i)));
            }
        }
        return result;
    }
    private LockStatus checkValidate(LockEntity lockEntity) {
        CAFContextInfo contextInfo=CAFContextResolverUtils.getCAFContextInfo();
        LockStatus result = LockStatus.Invalid;
        //1 锁不存在
        if (lockEntity == null) {
            return LockStatus.Unlocked;
        }
        //2 根据时间判断是否无效
        long seconds = lockEntity.getKeepTime().getSeconds();
        OffsetDateTime lockedTime = lockEntity.getLockTime();
        OffsetDateTime expirationTime = lockedTime.plus(seconds, ChronoUnit.SECONDS);
        OffsetDateTime currentTime =OffsetDateTime.now();
        if (seconds != 0 && (currentTime.compareTo(expirationTime) >= 0)) {
            return LockStatus.Invalid;                           // 表示锁存在但无效,后续可以加锁
        } else                                                              // 表示锁存在且有效，需要再检查
        {
            //3 根据范围(LockedScope)判断是否有效
            String locksessionId = lockEntity.getSessionId();
            String contextId = lockEntity.getContextId();
            String currentsessionId ="";// this.contextService.getSessionId();
            String currentContextId ="";// this.contextService.getContextId();
            if(contextInfo!=null){
                currentsessionId=contextInfo.getSessionId();
                currentContextId=contextInfo.getContextId();
            }
            switch (lockEntity.getLockedScope()) {
                case AppInstance:                             // 表示实例锁有效，需要近一步检查
                    result = LockStatus.Replaceable;
                    break;
                case Session:
                    //spi未扩展直接返回不可加锁
                    if(contextInfo==null){
                        result=LockStatus.Irreplaceable;
                        return result;
                    }
                    boolean notValid= this.isSessionNotValid(locksessionId);
                    //加日志排查自己锁自己问题
                    if(log.isInfoEnabled()){ //判断一把日志级别可减少序列化过程
                        log.info("locksession:"+locksessionId+"/currentsession:"+currentsessionId+"/notvalid:"+notValid);
                    }
                    if (!locksessionId.equals(currentsessionId) && notValid) {
                        return LockStatus.Invalid;               // 表示锁存在但进程丢失,后续可以加锁
                    }
                    result = LockStatus.Replaceable;
                    break;                                                // 进程锁需要进一步检查
                case BizContext:                                          // 功能上下文
                    //spi未扩展直接返回不可加锁
                    if(contextInfo==null){
                        result=LockStatus.Irreplaceable;
                        return result;
                    }
                    if (!contextId.equals(currentContextId) && this.isContextNotValid(contextId)) {
                        return LockStatus.Invalid;               // 表示锁存在但context无效,后续可以加锁
                    }
                    result = LockStatus.Replaceable;
                    break;
                default:
                    result = LockStatus.Invalid;
                    break;
            }
            //4 根据范围(ReplacedScope)判断是否可以替换
            String lockuserCode = lockEntity.getUserId();
            String currentuserCode ="";// this.contextService.getUserId();
            if(contextInfo!=null){
                currentuserCode=contextInfo.getUserId();
            }
            switch (lockEntity.getReplacedScope()) {
                case Exclusive:                             // 独占锁，不允许后续加锁
                    result = LockStatus.Irreplaceable;
                    return result;
                case Session:                               // 进程锁，如果本进程内可替换
                    //spi未扩展直接返回不可加锁
                    if(contextInfo==null){
                        result=LockStatus.Irreplaceable;
                        return result;
                    }
                    if (!locksessionId.equals(currentsessionId)) {
                        result = LockStatus.Irreplaceable;                // 其它进程的锁，不可加锁
                        return result;
                    }
                    break;
                case Self:
                    //spi未扩展直接返回不可加锁
                    if(contextInfo==null){
                        result=LockStatus.Irreplaceable;
                        return result;
                    }
                    //加日志排查自己锁自己问题
                    if(log.isInfoEnabled()){ //判断一把日志级别可减少序列化过程
                        log.info("lockuser:"+lockuserCode+"/currentuser:"+currentuserCode);
                    }
                    // 同一用户可替换，可能多个进程用同一用户登录
                    if (!currentuserCode.equals(lockuserCode)) {
                        result = LockStatus.Irreplaceable;                // 其它用户锁，不可加锁
                        return result;
                    }
                    break;
                case Share:                                 // 共享锁，可加锁
                    return LockStatus.Shared;
            }
            return result;
        }
    }


    private boolean isContextNotValid(String contextId) {
       return LockValidateResolverUtils.isContextNotValid(contextId);
    }

    /**
     * 检查会话是否有效
     *
     * @param sessionId
     * @return 会话的有效状态
     */
    private boolean isSessionNotValid(String sessionId) {
        return LockValidateResolverUtils.isSessionNotValid(sessionId);

    }

    private boolean tryRemoveLock(Throwable e){
        if(e==null){
            return false;
        }
        if(e instanceof SQLTransientConnectionException){
             return true;
        }else{
           return tryRemoveLock(e.getCause());
        }
    }



    //    private BatchLockResult tryAddBatchLock(String mkId,String dataCat,List<String> dataIds,String groupId,List<BatchLockEntity> entityList){
//        long time=System.currentTimeMillis();
//        BatchLockResult result=new BatchLockResult();
//        result.setGroupId(groupId);
//
//        //清理过期锁
//        this.batchRepo.deleteByExpiredTime(this.contextService.getCurrentDateTime());
//
//        //查询已有的锁数据
//        long time2=System.currentTimeMillis();
//        List<BatchLockEntity> entities = queryBatchLockEntityByDataIds(mkId, dataCat, dataIds);
//        if(log.isDebugEnabled()){
//            long cost2=System.currentTimeMillis()-time2;
//            log.debug("queryBatchLock: "+cost2+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
//        }
//        if (entities != null && entities.size() > 0) {
//            long time3=System.currentTimeMillis();
//            int count = deleteBatchLockBySession(entities);
//            if(log.isDebugEnabled()){
//                long cost3=System.currentTimeMillis()-time3;
//                log.debug("deleteBatchLock: "+cost3+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
//            }
//            if (entities.size() != count) {
//                result.setLockedEntities(entities);
//                result.setSuccess(false);
//                if(log.isInfoEnabled()){
//                    log.info("Cannot add lock.");
//                }
//                return result;
//            }
//        }
//        JpaTransaction tran = JpaTransaction.getTransaction();
//        try {
//                tran.begin(TransactionPropagation.REQUIRES_NEW);
//                EntityManager em = SpringBeanUtils.getBean(EntityManager.class);
//                if(batchSize==0){
//                    batchSize = CafEnvironment.getEnvironment().getProperty("spring.jpa.properties.jdbc.batch_size",Integer.class,10);
//                }
//                long time4=System.currentTimeMillis();
//                for (int i = 0; i < entityList.size(); i++) {
//                    em.persist(entityList.get(i));
//                    if ((i+1) % batchSize == 0 || i == entityList.size() - 1) {
//                        em.flush();
//                        em.clear();
//                    }
//                }
//                if(log.isDebugEnabled()){
//                    long cost4=System.currentTimeMillis()-time4;
//                    log.debug("saveBatchLock: "+cost4+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
//                }
//                result.setSuccess(true);
//                long time5=System.currentTimeMillis();
//                tran.commit();
//                if(log.isDebugEnabled()){
//                    long costCom=System.currentTimeMillis()-time5;
//                    long costTotal=System.currentTimeMillis()-time;
//                    log.debug("batchLockCommit: "+costCom+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
//                    log.debug("batchLockTime: "+costTotal+"ms"+" currentThread: "+Thread.currentThread().getId()+" resource: "+mkId+"-"+dataCat);
//                }
//                if(log.isInfoEnabled()){
//                    log.info("Add lock success.");
//                }
//                return result;
//        } catch (Throwable e) {
//                tran.rollback();
//            throw new io.iec.edp.caf.lock.service.api.exception.DistributedLockException("caf", DLErrorDefinition.AddBatchLock_Error,"addBatchLockError",e, ExceptionLevel.Error,false);
////                throw e;
//        }
//    }
}
